#include <stdio.h>
#include <math.h>
#include <glew.h>
#include <glut.h>
#include <Cg/cgGL.h>
#include <time.h>


#pragma comment( lib,"glew32.lib" )
#pragma comment( lib,"cg.lib" )
#pragma comment( lib,"cgGL.lib" )

void initCG(void);
void printVector(const float *p, const int N);
void setupTexture(const GLuint texID);

int N;
int texSizeX,texSizeY;

GLuint readID,writeID;

CGcontext cgContext;
CGprofile fragmentProfile;
CGprogram fragmentProgram;
CGparameter cgData;

GLuint fb;

GLuint glutWindowHandle;

float* data;


clock_t start,end;



int main(int argc, char **argv) {
			
	N = 36;	
	texSizeX=4;
	texSizeY=3;
	//texSize = (int)sqrt(N/3.0);
	data = new float[N];

	for (int i=0; i<N; i++) {
		data[i] = 1.0+i;
	}

	glutInit ( &argc, argv );
	glutWindowHandle = glutCreateWindow("GPGPU");
	glewInit();

	

	glGenFramebuffersEXT(1, &fb); 
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	
	gluOrtho2D(0.0, texSizeX, 0.0, texSizeY);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glViewport(0, 0, texSizeX, texSizeY);

	glGenTextures(1,&readID);
	glGenTextures(1,&writeID);

	glBindTexture(GL_TEXTURE_RECTANGLE_ARB,readID);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,0,GL_RGB32F_ARB,texSizeX,texSizeY,0,GL_RGB,GL_FLOAT,0);

	glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,0,0,0,texSizeX,texSizeY,GL_RGB,GL_FLOAT,data);	

	glBindTexture(GL_TEXTURE_RECTANGLE_ARB,writeID);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,0,GL_RGB32F_ARB,texSizeX,texSizeY,0,GL_RGB,GL_FLOAT,0);

	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	
	cgContext = cgCreateContext();
	fragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
	cgGLSetOptimalOptions(fragmentProfile);
	fragmentProgram = cgCreateProgramFromFile (cgContext, CG_SOURCE, "GP_F.cg", fragmentProfile, NULL, NULL);
	cgGLLoadProgram (fragmentProgram);
	cgData = cgGetNamedParameter (fragmentProgram, "textureY");

	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, writeID, 0);
	cgGLEnableProfile(fragmentProfile);
	cgGLBindProgram(fragmentProgram);
		
	glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);

	cgGLSetTextureParameter(cgData, readID);
	cgGLEnableTextureParameter(cgData);

	start=clock();

	glPolygonMode(GL_FRONT,GL_FILL);

	glBegin(GL_QUADS);
	glTexCoord2f(0.0, 0.0); 
	glVertex2f(0.0, 0.0);
	glTexCoord2f(texSizeX, 0.0); 
	glVertex2f(texSizeX, 0.0);
	glTexCoord2f(texSizeX, texSizeY); 
	glVertex2f(texSizeX, texSizeY);
	glTexCoord2f(0.0, texSizeY); 
	glVertex2f(0.0, texSizeY);
	glEnd();


	float* result = new float[N];

	glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
	glReadPixels(0, 0, texSizeX, texSizeY,GL_RGB,GL_FLOAT,result);


	for (int i=0; i<N; i++) 
		printf("%f\n",result[i]);

	end=clock();

	printf("%d",end-start);


	delete [] result;
	delete [] data;
	cgDestroyProgram(fragmentProgram);
	cgDestroyContext(cgContext);
	glDeleteFramebuffersEXT(1,&fb);
	glDeleteTextures(1,&readID);
	glDeleteTextures(1,&writeID);
	glutDestroyWindow (glutWindowHandle);

	return 0;
}
